home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / MSJV7_2B.ARJ / SRVRDEMO.C < prev    next >
C/C++ Source or Header  |  1992-03-01  |  36KB  |  1,334 lines

  1. /*                     
  2.   OLE SERVER DEMO
  3.   SrvrDemo.c                                               
  4.                                                                          
  5.   This file contains the window handlers, and various initialization and
  6.   utility functions.
  7.                                                                          
  8.   (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved        
  9. */
  10.  
  11.  
  12. #define SERVERONLY
  13. #include "Windows.h"
  14. #include "Ole.h"
  15. #include "SrvrDemo.h"
  16.  
  17. /* Global variable definitions */
  18.  
  19. HWND   hwndMain = NULL;
  20.  
  21. // Used in converting units from pixels to Himetric and vice-versa
  22. int    giXppli = NULL;       // pixels per logical inch along width
  23. int    giYppli = NULL;       // pixels per logical inch along height 
  24.  
  25. // Since this is a not an MDI app, there can be only one server and one doc.
  26. SRVR   srvrMain;
  27. DOC    docMain;
  28. char   szClient[cchFilenameMax];
  29. char   szClientDoc[cchFilenameMax];
  30.  
  31. // Has the user made changes to the document? 
  32. BOOL   fDocChanged = FALSE;
  33.  
  34. // Is this the first instance of this application currently running? 
  35. BOOL   fFirstInstance = TRUE;
  36.  
  37. // This flag is used when OleRevokeServerDoc returns OLE_WAIT_FOR_RELEASE,
  38. // and we must wait until DocRelease is called.
  39. BOOL   fWaitingForDocRelease = FALSE;
  40.  
  41. // This flag is used when OleRevokeServer returns OLE_WAIT_FOR_RELEASE,
  42. // and we must wait until SrvrRelease is called.
  43. BOOL   fWaitingForSrvrRelease = FALSE;
  44.  
  45. // This flag is set to TRUE after an application has called OleBlockServer
  46. // and now wishes to unblock the queued messages.  See WinMain.
  47. // Server Demo never sets fUnblock to TRUE because it never calls 
  48. // OleBlockServer.
  49. BOOL fUnblock = FALSE;
  50.  
  51. // Set this to FALSE if you want to guarantee that the server will not revoke
  52. // itself when SrvrRelease is called.  This is used in the IDM_NEW case and
  53. // the IDM_OPEN case (in OpenDoc).
  54. BOOL fRevokeSrvrOnSrvrRelease = TRUE;
  55.  
  56. // Version number, which is stored in the native data.
  57. VERSION version = 1;
  58.  
  59. HBRUSH hbrColor[chbrMax];
  60.  
  61. // Clipboard formats
  62. WORD   cfObjectLink;
  63. WORD   cfOwnerLink;
  64. WORD   cfNative;
  65.  
  66. // Method tables.
  67. OLESERVERDOCVTBL docvtbl;
  68. OLEOBJECTVTBL    objvtbl;
  69. OLESERVERVTBL    srvrvtbl;
  70.  
  71. HANDLE hInst;
  72. HANDLE hAccelTable;
  73. HMENU  hMainMenu = NULL;
  74.  
  75. // Window dimensions saved in private profile.
  76. static struct
  77. {
  78.    int nX;
  79.    int nY;
  80.    int nWidth;
  81.    int nHeight;
  82. } dimsSaved, dimsCurrent;
  83.  
  84.  
  85. static enum
  86. {
  87.    // Corresponds to the order of the menus in the .rc file.
  88.    menuposFile,
  89.    menuposEdit,
  90.    menuposColor,
  91.    menuposObject
  92. };               
  93.  
  94.  
  95. // Static functions.
  96. static void  DeleteInstance (void);
  97. static BOOL  ExitApplication (BOOL);
  98. static void  GetWord (LPSTR *plpszSrc, LPSTR lpszDst);
  99. static BOOL  InitApplication( HANDLE hInstance);
  100. static BOOL  InitInstance (HANDLE hInstance, BOOL fFirstInstance);
  101. static BOOL  ProcessCmdLine (LPSTR lpszLine, int nCmdShow, HWND hwndMain);
  102. static void  SaveDimensions (void);
  103. static void  SkipBlanks (LPSTR *plpsz);
  104. static void  UpdateObjMenus (void);
  105. static BOOL  FailedUpdate(HWND);
  106.  
  107. /* WinMain
  108.  * -------
  109.  *
  110.  * Standard windows entry point
  111.  *
  112.  * CUSTOMIZATION: None
  113.  *
  114.  */
  115. int PASCAL WinMain
  116.    (HANDLE  hInstance, HANDLE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
  117. {
  118.     MSG msg;
  119.  
  120.     if (!hPrevInstance)
  121.     {
  122.         fFirstInstance = TRUE;
  123.         if (!InitApplication(hInstance))
  124.             return FALSE;
  125.     }
  126.     else
  127.         fFirstInstance = FALSE;
  128.  
  129.     msg.wParam = FALSE;
  130.     
  131.     if (!InitInstance(hInstance, fFirstInstance))
  132.         goto errRtn;
  133.  
  134.     if (!InitServer (hwndMain, hInstance))
  135.         goto errRtn;
  136.  
  137.     if (!ProcessCmdLine (lpCmdLine, nCmdShow, hwndMain))
  138.     {
  139.         ExitApplication(FALSE);
  140.         goto errRtn;
  141.     }
  142.  
  143.     for (;;)
  144.     {
  145.          // Your application should set fUnblock to TRUE when it decides
  146.          // to unblock.
  147.          if (fUnblock)
  148.          {
  149.             BOOL fMoreMsgs = TRUE;
  150.             while (fMoreMsgs)
  151.             {
  152.                OleUnblockServer (srvrMain.lhsrvr, &fMoreMsgs);
  153.             }
  154.             // We have taken care of all the messages in the OLE queue
  155.             fUnblock = FALSE;
  156.          }
  157.       
  158.          if (!GetMessage(&msg, NULL, NULL, NULL)) 
  159.             break;
  160.          if( !TranslateAccelerator(hwndMain, hAccelTable, &msg)) 
  161.          {
  162.                TranslateMessage(&msg);
  163.                DispatchMessage(&msg); 
  164.          }
  165.     }
  166.  
  167.     
  168. errRtn:
  169.     DeleteInstance ();
  170.     return (msg.wParam);
  171. }
  172.  
  173.  
  174.  
  175. /* InitApplication
  176.  * ---------------
  177.  *
  178.  * Initialize the application - register the window classes
  179.  *
  180.  * HANDLE hInstance
  181.  * 
  182.  * RETURNS: TRUE if classes are properly registered.
  183.  *          FALSE otherwise
  184.  *
  185.  * CUSTOMIZATION: Re-implement
  186.  *
  187.  */
  188. static BOOL InitApplication( HANDLE hInstance )
  189. {
  190.     WNDCLASS  wc;
  191.  
  192.     wc.lpszClassName = "MainClass";
  193.     wc.lpfnWndProc   = MainWndProc;
  194.     wc.style         = NULL;
  195.     wc.cbClsExtra    = 4;
  196.     wc.cbWndExtra    = 0;
  197.     wc.hInstance     = hInstance;
  198.     wc.hIcon         = LoadIcon(hInstance, "DocIcon");
  199.     wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  200.     wc.hbrBackground = GetStockObject(WHITE_BRUSH);
  201.     wc.lpszMenuName  = "MainMenu";
  202.  
  203.     if (!RegisterClass(&wc))
  204.         return FALSE;
  205.  
  206.     wc.lpszClassName = "ObjClass";
  207.     wc.lpfnWndProc   = ObjWndProc;
  208.     wc.hIcon         = NULL;
  209.     wc.cbWndExtra    = cbWindExtra;
  210.     wc.lpszMenuName  = NULL;
  211.     wc.hCursor       = LoadCursor(NULL, IDC_CROSS);
  212.  
  213.     if (!RegisterClass(&wc))
  214.         return FALSE;
  215.  
  216.     return TRUE;
  217. }
  218.  
  219.  
  220.  
  221. /* InitInstance
  222.  * ------------
  223.  *
  224.  * Create brushes used by the program, the main window, and 
  225.  * do any other per-instance initialization.
  226.  *
  227.  * HANDLE hInstance
  228.  * 
  229.  * RETURNS: TRUE if successful 
  230.  *          FALSE otherwise.
  231.  *
  232.  * CUSTOMIZATION: Re-implement
  233.  *
  234.  */
  235. static BOOL InitInstance (HANDLE hInstance, BOOL fFirstInstance)
  236. {
  237.     long rglColor [chbrMax] = 
  238.     {
  239.       0x000000ff,  // Red
  240.       0x0000ff00,  // Green
  241.       0x00ff0000,  // Blue
  242.       0x00ffffff,  // White
  243.       0x00808080,  // Gray
  244.       0x00ffff00,  // Cyan
  245.       0x00ff00ff,  // Magenta
  246.       0x0000ffff   // Yellow
  247.     };
  248.  
  249.  
  250.     int iColor;
  251.     HDC hDC;
  252.     
  253.     hInst = hInstance;
  254.  
  255.     // Initialize the method tables.
  256.     InitVTbls ();
  257.  
  258.     // Initialize the brushes used.
  259.     for (iColor = 0; iColor < chbrMax; iColor++)
  260.       hbrColor[iColor] = CreateSolidBrush (rglColor[iColor]);
  261.  
  262.     // Register clipboard formats.
  263.     cfObjectLink= RegisterClipboardFormat ("ObjectLink");
  264.     cfOwnerLink = RegisterClipboardFormat ("OwnerLink");
  265.     cfNative    = RegisterClipboardFormat ("Native");
  266.  
  267.     hAccelTable = LoadAccelerators(hInst, "Accelerators");
  268. //    hMainMenu   = LoadMenu(hInst, "MainMenu");
  269.  
  270.  
  271.     hwndMain = CreateWindow(
  272.         "MainClass",
  273.         szAppName,
  274.         WS_OVERLAPPEDWINDOW,
  275.         CW_USEDEFAULT, CW_USEDEFAULT,
  276.         3*OBJECT_WIDTH, 3*OBJECT_HEIGHT,
  277.         NULL,
  278.         NULL,
  279.         hInstance,
  280.         NULL
  281.     );
  282.  
  283.  
  284.     if (!hwndMain)
  285.         return FALSE;
  286.  
  287.     szClient[0] = NULL;
  288.     lstrcpy (szClientDoc, "Client Document");
  289.     
  290.     // Initialize global variables with LOGPIXELSX and LOGPIXELSY
  291.         
  292.     hDC    = GetDC (NULL);       // Get the hDC of the desktop window
  293.     giXppli = GetDeviceCaps (hDC, LOGPIXELSX);
  294.     giYppli = GetDeviceCaps (hDC, LOGPIXELSY);
  295.     ReleaseDC (NULL, hDC);
  296.  
  297.     return TRUE;
  298.  
  299. }
  300.  
  301.  
  302.  
  303. /* DeleteInstance
  304.  * --------------
  305.  *
  306.  * Deallocate the VTables, and the brushes created for this instance
  307.  *
  308.  *
  309.  * CUSTOMIZATION: The call to FreeVTbls must remain.
  310.  *
  311.  */
  312. static void DeleteInstance (void)
  313. {
  314.     int i;
  315.  
  316.     // Free the method table instances.
  317.     FreeVTbls ();
  318.  
  319.     for (i = 0; i < chbrMax; i++)
  320.         DeleteObject (hbrColor[i]);
  321. }
  322.  
  323.  
  324.  
  325. /* ExitApplication
  326.  * ---------------
  327.  *
  328.  * Handles the WM_CLOSE and WM_COMMAND/IDM_EXIT messages.
  329.  *
  330.  * RETURNS: TRUE if application should really terminate
  331.  *          FALSE if not
  332.  *
  333.  *
  334.  * CUSTOMIZATION: None
  335.  *
  336.  */
  337. static BOOL ExitApplication (BOOL fUpdateLater)
  338. {
  339.  
  340.    if (fUpdateLater)
  341.    {
  342.       // The non-standard OLE client did not accept the update
  343.       // when we requested it, so we are sending the client 
  344.       // OLE_CLOSED now that we are closing the document.
  345.       SendDocMsg (OLE_CLOSED);
  346.    }
  347.  
  348.    if (StartRevokingServer() == OLE_WAIT_FOR_RELEASE)
  349.       Wait (&fWaitingForSrvrRelease);
  350.    /* SrvrRelease will not necessarily post a WM_QUIT message.
  351.       If the document is not embedded, SrvrRelease by itself does
  352.       not cause the application to terminate.  But now we want it to.
  353.    */
  354.    if (docMain.doctype != doctypeEmbedded)
  355.       PostQuitMessage(0);
  356.    SaveDimensions();
  357.    return TRUE;
  358. }
  359.  
  360.  
  361.  
  362. /* MainWndProc
  363.  * -----------
  364.  *
  365.  * Main window message handler.
  366.  *
  367.  *
  368.  * CUSTOMIZATION: Remove the color menu and the object menu entirely.  
  369.  *                Add handlers for your application's menu items and any 
  370.  *                Windows messages your application needs to handle.  
  371.  *                The handlers for the menu items that involve OLE
  372.  *                can be added to, but no logic should be removed.
  373.  *                    
  374.  *
  375.  */
  376. long FAR PASCAL MainWndProc
  377.    (HWND hwnd, unsigned message, WORD wParam, LONG lParam )
  378. {
  379.     LPOBJ     lpobj;
  380.  
  381.     switch (message) 
  382.     {
  383.         case WM_COMMAND:
  384.  
  385.             if (fWaitingForDocRelease)
  386.             {
  387.                ErrorBox ("Waiting for a document to be revoked.\n\rPlease wait.");
  388.                return NULL;
  389.             }
  390.  
  391.             switch (wParam) 
  392.             {
  393.                case IDM_EXIT:
  394.                   SendMessage(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0L);
  395.                   break;
  396.  
  397.                case IDM_ABOUT:
  398.                {
  399.                   FARPROC lpProcAbout = MakeProcInstance(About, hInst);
  400.                   DialogBox(hInst, "AboutBox", hwnd, lpProcAbout);
  401.                   FreeProcInstance(lpProcAbout);
  402.                   break;
  403.                }
  404.  
  405.    
  406.                case IDM_NEW:
  407.                {
  408.                   BOOL fUpdateLater;
  409.                   OLESTATUS olestatus;
  410.  
  411.                   if (SaveChangesOption (&fUpdateLater) == IDCANCEL)
  412.                      break;
  413.                   else if (fUpdateLater)
  414.                      SendDocMsg (OLE_CLOSED);
  415.  
  416.                   // We want to revoke the doc but not the server, so if
  417.                   // SrvrRelease is called, do not revoke server.
  418.                   fRevokeSrvrOnSrvrRelease = FALSE;
  419.  
  420.                   if ((olestatus = RevokeDoc()) > OLE_WAIT_FOR_RELEASE) 
  421.                   {   
  422.                      ErrorBox ("Serious Error: Cannot revoke document.");
  423.                      break;
  424.                   }
  425.                   else if (olestatus == OLE_WAIT_FOR_RELEASE)
  426.                      Wait (&fWaitingForDocRelease);
  427.   
  428.                   fRevokeSrvrOnSrvrRelease = TRUE;
  429.  
  430.                   if (!CreateNewDoc (NULL, "(Untitled)", doctypeNew))
  431.                   {
  432.                      ErrorBox ("Serious Error: Cannot create new document.");
  433.                      break;
  434.                   }
  435.                   // Your application need not create a default object.
  436.                   CreateNewObj (FALSE);
  437.                   EmbeddingModeOff();
  438.                   break;
  439.                }
  440.                case IDM_OPEN:
  441.                   OpenDoc();
  442.                   UpdateObjMenus();
  443.                   break;
  444.  
  445.                case IDM_SAVE:
  446.                   SaveDoc();
  447.                   break;
  448.  
  449.                case IDM_SAVEAS:
  450.                   if (!SaveDocAs ())
  451.                      break;
  452.                   if (docMain.doctype != doctypeEmbedded)
  453.                      EmbeddingModeOff();
  454.                   break;
  455.  
  456.                case IDM_UPDATE:
  457.                   switch (OleSavedServerDoc (docMain.lhdoc))
  458.                   {
  459.                      case OLE_ERROR_CANT_UPDATE_CLIENT:
  460.                         if (!FailedUpdate(hwnd))
  461.                            ExitApplication(TRUE);
  462.                         break;
  463.                      case OLE_OK:
  464.                         break;
  465.                      default:
  466.                         ErrorBox ("Serious Error: Cannot update.");
  467.                   }
  468.                   break;
  469.  
  470.                /* Color menu */
  471.  
  472.                case IDM_RED:
  473.                case IDM_GREEN:
  474.                case IDM_BLUE:
  475.                case IDM_WHITE:
  476.                case IDM_GRAY:
  477.                case IDM_CYAN:
  478.                case IDM_MAGENTA:
  479.                case IDM_YELLOW:
  480.                   lpobj = SelectedObject();
  481.                   lpobj->native.idmColor = wParam;
  482.                   // Recolor the object on the screen.
  483.                   InvalidateRect (lpobj->hwnd, (LPRECT)NULL,  TRUE);
  484.                   UpdateWindow (lpobj->hwnd);
  485.                   fDocChanged = TRUE;
  486.                   if (docMain.doctype == doctypeFromFile)
  487.                      // If object is linked, update it in client now. 
  488.                      SendObjMsg (lpobj, OLE_CHANGED);
  489.                   break;
  490.  
  491.                /* Edit menu */
  492.  
  493.                case IDM_COPY:
  494.                   CutOrCopyObj (TRUE);
  495.                   break;
  496.  
  497.                case IDM_CUT:
  498.                   CutOrCopyObj (FALSE);
  499.                   // Fall through.
  500.  
  501.                case IDM_DELETE:
  502.                   RevokeObj (SelectedObject());
  503.                   DestroyWindow (SelectedObjectWindow());
  504.                   UpdateObjMenus();
  505.                   break;
  506.  
  507.                /* Object menu */
  508.  
  509.                case IDM_NEXTOBJ:
  510.                   lpobj = SelectedObject();
  511.                   /* The 1 in the second parameter puts the current window
  512.                      at the bottom of the current window list. */
  513.                   SetWindowPos(lpobj->hwnd, 1, 0,0,0,0,
  514.                               SWP_NOMOVE | SWP_NOSIZE);
  515.                   break;
  516.  
  517.                case IDM_NEWOBJ:
  518.                   lpobj = CreateNewObj (TRUE);
  519.                   BringWindowToTop(lpobj->hwnd);
  520.                   break;
  521.  
  522.                default:
  523.                   ErrorBox ("Unknown Command.");
  524.                   break;
  525.             }         
  526.             break;
  527.  
  528.  
  529.         case WM_NCCALCSIZE:
  530.             if (!IsIconic(hwnd) && !IsZoomed(hwnd))
  531.             {
  532.                 dimsCurrent.nX = ((LPRECT)lParam)->left;
  533.                 dimsCurrent.nWidth = ((LPRECT)lParam)->right - dimsCurrent.nX;
  534.                 dimsCurrent.nY = ((LPRECT)lParam)->top;
  535.                 dimsCurrent.nHeight = ((LPRECT)lParam)->bottom - dimsCurrent.nY;
  536.             }
  537.             return DefWindowProc(hwnd, message, wParam, lParam);
  538.             break;
  539.  
  540.         case WM_QUERYENDSESSION:
  541.         {
  542.             BOOL fUpdateLater;
  543.  
  544.             if (SaveChangesOption(&fUpdateLater) == IDCANCEL)
  545.                return FALSE;
  546.  
  547.             if (fUpdateLater)
  548.             {
  549.                // The non-standard OLE client did not accept the update
  550.                // when we requested it, so we are sending the client 
  551.                // OLE_CLOSED now that we are closing the document.
  552.                SendDocMsg (OLE_CLOSED);
  553.             }                          
  554.             return TRUE;
  555.         }
  556.  
  557.         case WM_CLOSE:
  558.          {
  559.             BOOL fUpdateLater;
  560.  
  561.             if (SaveChangesOption(&fUpdateLater) != IDCANCEL)
  562.                ExitApplication(fUpdateLater);
  563.             break;
  564.          }
  565.  
  566.         default:
  567.             return DefWindowProc(hwnd, message, wParam, lParam);
  568.     }
  569.     return NULL;
  570. }
  571.  
  572.  
  573.  
  574. /* About
  575.  * -----
  576.  *
  577.  * "About Box" dialog handler.
  578.  *
  579.  * CUSTOMIZATION: None
  580.  *
  581.  */
  582. BOOL FAR PASCAL About (HWND hDlg, unsigned message, WORD wParam, LONG lParam)
  583. {
  584.     switch (message) 
  585.     {
  586.         case WM_INITDIALOG:
  587.             return TRUE;
  588.  
  589.         case WM_COMMAND:
  590.             if (wParam == IDOK || wParam == IDCANCEL) 
  591.             {
  592.                 EndDialog(hDlg, TRUE);
  593.                 return TRUE;
  594.             }
  595.             break;
  596.     }
  597.     return FALSE;
  598. }
  599.  
  600.  
  601.  
  602.  
  603. /* ObjWndProc
  604.  * ----------
  605.  *
  606.  * Message handler for the object windows.
  607.  *
  608.  *
  609.  * CUSTOMIZATION: Server Demo specific
  610.  *
  611.  */
  612. long FAR PASCAL ObjWndProc 
  613.    (HWND hwnd, unsigned message, WORD wParam, LONG lParam)
  614. {
  615.     static BOOL    fCapture = FALSE;
  616.     static struct  {RECT rect; POINT pt;} drag;
  617.     static RECT    rectMain;
  618.  
  619.     switch (message) 
  620.     {
  621.         case WM_CREATE:
  622.         {
  623.             LPOBJ          lpobj;
  624.             LPCREATESTRUCT lpcs;
  625.             // The call to CreateWindow puts lpobj into lpCreateParams
  626.             lpcs = (LPCREATESTRUCT) lParam;
  627.             lpobj = (LPOBJ) lpcs->lpCreateParams;
  628.             // Associate the window just created with the object.
  629.             lpobj->hwnd = hwnd;
  630.             /* Store pointer to object in the window structure. */
  631.             SetWindowLong(hwnd, ibLpobj, (LONG) lpobj);
  632.             UpdateObjMenus ();
  633.             break;
  634.         }
  635.         case WM_SIZE:
  636.         {
  637.             RECT rect;
  638.             if (fWaitingForDocRelease)
  639.             {   
  640.                ErrorBox ("Waiting for a document to be revoked.\n\rPlease wait.");
  641.                return NULL;
  642.             }
  643.             // Get coordinates of object relative to main window's client area.
  644.             GetWindowRect (hwnd, (LPRECT)&rect);
  645.             ScreenToClient (hwndMain, (LPPOINT)&rect);
  646.             ScreenToClient (hwndMain, (LPPOINT)&rect.right);
  647.             SizeObj (hwnd, rect, TRUE);
  648.             // Fall through.
  649.         }
  650.         case WM_PAINT:
  651.             PaintObj (hwnd);
  652.             break;
  653.  
  654.         case WM_LBUTTONDOWN:
  655.             if (fWaitingForDocRelease)
  656.             {   
  657.                ErrorBox ("Waiting for a document to be revoked.\n\rPlease wait.");
  658.                return NULL;
  659.             }
  660.             BringWindowToTop (hwnd);
  661.  
  662.             GetWindowRect (hwnd, (LPRECT) &drag.rect);
  663.             ScreenToClient (hwndMain, (LPPOINT)&drag.rect.left);
  664.             ScreenToClient (hwndMain, (LPPOINT)&drag.rect.right);
  665.  
  666.             drag.pt.x = LOWORD(lParam);
  667.             drag.pt.y = HIWORD(lParam);
  668.  
  669.             // Convert drag.pt to the main window's client coordinates.
  670.             ClientToScreen (hwnd, (LPPOINT)&drag.pt);
  671.             ScreenToClient (hwndMain, (LPPOINT)&drag.pt);
  672.  
  673.             // Remember the coordinates of the main window so we do not drag
  674.             // an object outside the main window.
  675.             GetClientRect (hwndMain, (LPRECT) &rectMain);
  676.  
  677.             SetCapture (hwnd);
  678.             fCapture = TRUE;
  679.             break;
  680.  
  681.         case WM_MOUSEMOVE:
  682.         {
  683.             HDC   hdc;
  684.             POINT pt;
  685.  
  686.             if (!fCapture)
  687.                 break;
  688.  
  689.             fDocChanged = TRUE;
  690.             pt.x = LOWORD(lParam);
  691.             pt.y = HIWORD(lParam);
  692.  
  693.             // Convert pt to the main window's client coordinates.
  694.             ClientToScreen (hwnd, (LPPOINT)&pt);
  695.             ScreenToClient (hwndMain, (LPPOINT)&pt);
  696.  
  697.             if (!PtInRect (&rectMain, pt))
  698.                break;
  699.  
  700.             hdc = GetDC(hwndMain);
  701.  
  702.             // Erase old drag rectangle
  703.             InvertRect (hdc, (LPRECT)&drag.rect);
  704.                   
  705.             // Update drag.rect
  706.             OffsetRect (&drag.rect, pt.x - drag.pt.x, pt.y - drag.pt.y);
  707.  
  708.             // Update drag.pt
  709.             drag.pt.x = pt.x;
  710.             drag.pt.y = pt.y;
  711.  
  712.             // Show new drag rectangle
  713.             InvertRect (hdc, (LPRECT)&drag.rect);
  714.             ReleaseDC (hwndMain, hdc);
  715.             break;
  716.         }
  717.  
  718.         case WM_LBUTTONUP:
  719.         {
  720.             LPOBJ          lpobj;
  721.             if (!fCapture)
  722.                 return TRUE;
  723.  
  724.             fCapture = FALSE;
  725.             ReleaseCapture ();
  726.  
  727.             MoveWindow (hwnd, drag.rect.left, drag.rect.top,
  728.                         drag.rect.right - drag.rect.left,
  729.                         drag.rect.bottom - drag.rect.top, TRUE);
  730.             InvalidateRect (hwnd, (LPRECT)NULL, TRUE);
  731.             lpobj = HwndToLpobj (hwnd);
  732.             lpobj->native.nX = drag.rect.left;
  733.             lpobj->native.nY = drag.rect.top;
  734.             break;
  735.         }
  736.         case WM_DESTROY:
  737.             DestroyObj (hwnd);
  738.             return DefWindowProc(hwnd, message, wParam, lParam);
  739.  
  740.         default:
  741.             return DefWindowProc(hwnd, message, wParam, lParam);
  742.     }
  743.     return NULL;
  744. }
  745.  
  746.  
  747.  
  748. /* DeviceToHiMetric
  749.  * ----------------
  750.  *
  751.  * Converts a point from device units to HiMetric units.
  752.  * This function is designed to be generic enough to be reused.
  753.  *
  754.  * HWND hwnd    - The window whose display context is to be used
  755.  * LPPOINT lppt - The point to be converted.
  756.  *
  757.  * CUSTOMIZATION: None
  758.  *
  759.  */
  760. void DeviceToHiMetric (HWND hwnd, LPPOINT lppt)
  761. {
  762.     lppt->x = MulDiv (lppt->x, HIMETRIC_PER_INCH, giXppli);
  763.     lppt->y = MulDiv (lppt->y, HIMETRIC_PER_INCH, giYppli);
  764. }
  765.  
  766.  
  767. /* UpdateFileMenu
  768.  * --------------
  769.  *
  770.  * Updates the "Update <Client doc>" and "Exit & Return to <Client doc>" 
  771.  * with the currently set client document name
  772.  *
  773.  * CUSTOMIZATION: Re-implement
  774.  *
  775.  */
  776. void UpdateFileMenu (int iSaveUpdateId)
  777. {
  778.     char    str[cchFilenameMax];
  779.     HMENU   hMenu = GetMenu(hwndMain);    
  780.  
  781.     /* Change File menu so it contains "Update" instead of "Save". */
  782.     
  783.     lstrcpy (str, "&Update ");
  784.     lstrcat (str, szClientDoc);
  785.     ModifyMenu(hMenu, iSaveUpdateId, MF_BYCOMMAND|MF_STRING, IDM_UPDATE, str);
  786.     
  787.     /* Change File menu so it contains "Exit & Return to <client doc>" */
  788.     /* instead of just "Exit" */
  789.     
  790.     lstrcpy (str, "E&xit && Return to ");
  791.     lstrcat (str, szClientDoc);
  792.     ModifyMenu(hMenu, IDM_EXIT, MF_BYCOMMAND|MF_STRING, IDM_EXIT, str);
  793. }
  794.  
  795.  
  796.  
  797. /* EmbeddingModeOn
  798.  * ---------------
  799.  *
  800.  * Do whatever is necessary for the application to start "embedding mode."
  801.  *
  802.  * CUSTOMIZATION: Re-implement
  803.  *
  804.  */
  805. void EmbeddingModeOn(void) 
  806. {
  807.     HMENU hMenu = GetMenu(hwndMain);
  808.  
  809.     UpdateFileMenu (IDM_SAVE);
  810.  
  811.     /* Change File menu so it contains "Save Copy As..." instead of */
  812.     /* "Save As..." */
  813.     ModifyMenu(hMenu, IDM_SAVEAS, MF_BYCOMMAND|MF_STRING, IDM_SAVEAS, 
  814.         "Save Copy As..");
  815.     
  816.     /* In embedded mode, the user can edit only the embedded object, not
  817.        create new ones. */
  818.     EnableMenuItem(hMenu, menuposObject, MF_BYPOSITION | MF_GRAYED);
  819.     EnableMenuItem(hMenu, IDM_CUT,     MF_BYCOMMAND | MF_GRAYED);
  820.     EnableMenuItem(hMenu, IDM_DELETE,  MF_BYCOMMAND | MF_GRAYED);
  821.     DrawMenuBar (hwndMain);
  822. }
  823.  
  824.  
  825.  
  826.  
  827. /* EmbeddingModeOff
  828.  * ----------------
  829.  *
  830.  * Do whatever is necessary for the application to end "embedding mode."
  831.  *
  832.  * CUSTOMIZATION: Re-implement
  833.  *
  834.  */
  835. void EmbeddingModeOff (void) 
  836. {
  837.     HMENU hMenu = GetMenu(hwndMain);
  838.  
  839.     /* Change File menu so it contains "Save" instead of "Update". */
  840.     ModifyMenu(hMenu, IDM_UPDATE, MF_BYCOMMAND | MF_STRING, IDM_SAVE, "&Save");
  841.     /* Change File menu so it contains "Exit & Return to <client doc>" */
  842.     /* instead of just "Exit" */
  843.     ModifyMenu(hMenu, IDM_EXIT, MF_BYCOMMAND | MF_STRING, IDM_EXIT, "E&xit");
  844.  
  845.     /* Change File menu so it contains "Save As..." instead of */
  846.     /* "Save Copy As..." */
  847.     ModifyMenu(hMenu, IDM_SAVEAS, MF_BYCOMMAND|MF_STRING, IDM_SAVEAS, 
  848.         "Save As..");
  849.     
  850.     /* In non-embedded mode, the user can create new objects. */
  851.     EnableMenuItem(hMenu, menuposObject, MF_BYPOSITION | MF_ENABLED);
  852.     
  853.     lstrcpy (szClientDoc, "Client Document");
  854.     DrawMenuBar (hwndMain);
  855. }
  856.  
  857.  
  858.  
  859. /* ErrorBox
  860.  * --------
  861.  *
  862.  * char *szMessage - String to display inside message box.
  863.  *
  864.  * CUSTOMIZATION: Server Demo specific
  865.  *
  866.  */
  867. void ErrorBox (char *szMessage)
  868. {
  869.    MessageBox (hwndMain, szMessage, szAppName, MB_OK);
  870. }
  871.  
  872.  
  873.  
  874. /* GetWord
  875.  * -------
  876.  *
  877.  * LPSTR *plpszSrc - Pointer to a pointer to a source string
  878.  * LPSTR lpszDst   - Pointer to destination buffer
  879.  *
  880.  * Will copy one space-terminated or null-terminated word from the source
  881.  * string to the destination buffer.
  882.  * When done, *plpszSrc will point to the character after the word. 
  883.  * 
  884.  * CUSTOMIZATION: Server Demo specific
  885.  *
  886.  */
  887. static void GetWord (LPSTR *plpszSrc, LPSTR lpszDst)
  888. {
  889.    int i = 0;
  890.    while (**plpszSrc && **plpszSrc != ' ')
  891.    {
  892.          lpszDst[i++] = *(*plpszSrc)++;
  893.    }
  894.    lpszDst[i] = '\0';
  895. }
  896.  
  897.  
  898.  
  899. /* HiMetricToDevice 
  900.  * ----------------
  901.  *
  902.  * Converts a point from HiMetric units to device units.
  903.  * This function is designed to be generic enough to be reused.
  904.  *
  905.  * HWND hwnd    - The window whose display context is to be used
  906.  * LPPOINT lppt - The point to be converted.
  907.  *
  908.  * CUSTOMIZATION: None
  909.  *
  910.  */
  911. void HiMetricToDevice (HWND hwnd, LPPOINT lppt)
  912. {
  913.     lppt->x = MulDiv (giXppli, lppt->x, HIMETRIC_PER_INCH);
  914.     lppt->y = MulDiv (giYppli, lppt->y, HIMETRIC_PER_INCH);
  915. }
  916.  
  917.  
  918.  
  919. /* HwndToLpobj
  920.  * -----------
  921.  *
  922.  * Given an object's window, return a pointer to the object.
  923.  * The GetWindowLong call extracts an LPOBJ from the extra data stored with
  924.  * the window.
  925.  *
  926.  * HWND hwndObj - Handle to the object's window
  927.  *
  928.  * RETURNS: A pointer to the object
  929.  *
  930.  * CUSTOMIZATION: Server Demo specific
  931.  *
  932.  */
  933. LPOBJ HwndToLpobj (HWND hwndObj)
  934. {
  935.    return (LPOBJ) GetWindowLong (hwndObj, ibLpobj);
  936. }
  937.  
  938.  
  939.  
  940. /* CreateUntitledDoc
  941.  * -----------------
  942.  *
  943.  * Create a fresh document with one object.
  944.  *
  945.  * RETURNS: TRUE if successful
  946.  *          FALSE otherwise
  947.  *
  948.  * CUSTOMIZATION: Re-implement 
  949.  *
  950.  */
  951. static BOOL CreateUntitledDoc (int nCmdShow)
  952. {
  953.       if (!CreateNewDoc (NULL, "(Untitled)", doctypeNew))
  954.          return FALSE;
  955.       CreateNewObj (FALSE);
  956.       ShowWindow(hwndMain, nCmdShow);
  957.       UpdateWindow(hwndMain);
  958.       return TRUE;
  959. }
  960.  
  961.  
  962. /* ProcessCmdLine
  963.  * --------------
  964.  *
  965.  * Parses the Windows command line which was passed to WinMain.
  966.  *
  967.  * Case One: SrvrDemo.exe 
  968.  *   fEmbedding = FALSE
  969.  *   Create an untitled document.
  970.  *
  971.  * Case two: SrvrDemo.exe filename
  972.  *   fEmbedding = FALSE
  973.  *   Create a new document from the file.
  974.  *
  975.  * Case three: SrvrDemo.exe -Embedding
  976.  *   fEmbedding = TRUE
  977.  *   Do not create or register a document.
  978.  *   Do not show window until client requests it.
  979.  * 
  980.  * Case four: SrvrDemo.exe -Embedding filename
  981.  *   fEmbedding = TRUE
  982.  *   Load file.
  983.  *   Call OleRegisterServerDoc.
  984.  *   Do not show window until client requests it.
  985.  *
  986.  * 
  987.  * LPSTR lpszLine - The Windows command line
  988.  * int nCmdShow   - Parameter to WinMain
  989.  * HWND hwndMain  - The application's main window
  990.  * 
  991.  * RETURNS: TRUE  if the command line was processed correctly.
  992.  *          FALSE if a filename was specified which did not
  993.  *                contain a proper document.
  994.  *
  995.  * CUSTOMIZATION: None.
  996.  *
  997.  */
  998. static BOOL ProcessCmdLine (LPSTR lpszLine, int nCmdShow, HWND hwndMain)
  999. {
  1000.    char     szBuf[cchFilenameMax];
  1001.    BOOL     fEmbedding = FALSE;  // Is "-Embedding" on the command line?
  1002.    int      i=0;
  1003.    OFSTRUCT of;
  1004.  
  1005.    if (!*lpszLine)    // No filename or options, so start a fresh document.
  1006.    {
  1007.       return CreateUntitledDoc(nCmdShow);
  1008.    }
  1009.     
  1010.    SkipBlanks (&lpszLine);
  1011.  
  1012.    // Check for "-Embedding" or "/Embedding" and set fEmbedding.
  1013.    if(*lpszLine == '-' || *lpszLine == '/')
  1014.    {
  1015.       lpszLine++;
  1016.       GetWord (&lpszLine, szBuf);
  1017.       fEmbedding = !lstrcmp(szBuf, szEmbeddingFlag);
  1018.    }
  1019.  
  1020.    SkipBlanks (&lpszLine);
  1021.  
  1022.    if (*lpszLine) // if there is a filename
  1023.    {
  1024.       // Put filename into szBuf.
  1025.       GetWord (&lpszLine, szBuf);
  1026.  
  1027.       if (-1 == OpenFile(szBuf, &of, OF_READ | OF_EXIST))
  1028.       {
  1029.          // File not found
  1030.          if (fEmbedding)
  1031.             return FALSE;       
  1032.          else
  1033.          {
  1034.             char sz[100];
  1035.             wsprintf (sz, "File %s not found.", (LPSTR) szBuf);
  1036.             ErrorBox (sz);
  1037.             return CreateUntitledDoc(nCmdShow);
  1038.          }
  1039.       }
  1040.  
  1041.       if (!CreateDocFromFile (szBuf, NULL, doctypeFromFile))
  1042.       {
  1043.          // File not in proper format.
  1044.          if (fEmbedding)
  1045.             return FALSE;       
  1046.          else
  1047.          {
  1048.             char sz[100];
  1049.             wsprintf (sz, "File %s not in proper format.", (LPSTR) szBuf);
  1050.             ErrorBox (sz);
  1051.             return CreateUntitledDoc(nCmdShow);
  1052.          }
  1053.       }
  1054.    }
  1055.  
  1056.    if (fEmbedding)
  1057.    {
  1058.       /* Do not show window until told to do so by client. */
  1059.       ShowWindow(hwndMain, SW_HIDE);
  1060.    }
  1061.    else
  1062.    {
  1063.       ShowWindow(hwndMain, nCmdShow);
  1064.       UpdateWindow(hwndMain);
  1065.    }
  1066.    return TRUE;
  1067. }
  1068.  
  1069.  
  1070.  
  1071. /* SaveDimensions
  1072.  * --------------
  1073.  *
  1074.  * Save the dimensions of the main window in a private profile file.
  1075.  *
  1076.  * CUSTOMIZATION: This function may be removed.  If you wish to support
  1077.  *                intelligent window placement, then the only necessary
  1078.  *                change is to change the string "SrvrDemo.Ini" to a filename
  1079.  *                appropriate for your application.
  1080.  */
  1081. static void SaveDimensions (void)
  1082. {
  1083.    if ((dimsCurrent.nX != dimsSaved.nX) || 
  1084.          (dimsCurrent.nY != dimsSaved.nY) ||
  1085.          (dimsCurrent.nWidth != dimsSaved.nWidth) || 
  1086.          (dimsCurrent.nHeight != dimsSaved.nHeight) )
  1087.    {
  1088.          // Save current window dimensions to private profile.
  1089.          char szBuf[7];
  1090.          wsprintf (szBuf, "%d", dimsCurrent.nX);
  1091.          WritePrivateProfileString
  1092.          (szAppName, "x", szBuf, "SrvrDemo.Ini");
  1093.          wsprintf (szBuf, "%d", dimsCurrent.nY);
  1094.          WritePrivateProfileString
  1095.          (szAppName, "y", szBuf, "SrvrDemo.Ini");
  1096.          wsprintf (szBuf, "%d", dimsCurrent.nWidth);
  1097.          WritePrivateProfileString
  1098.          (szAppName, "w", szBuf, "SrvrDemo.Ini");
  1099.          wsprintf (szBuf, "%d", dimsCurrent.nHeight);
  1100.          WritePrivateProfileString
  1101.          (szAppName, "h", szBuf, "SrvrDemo.Ini");
  1102.    }
  1103. }
  1104.  
  1105.  
  1106.  
  1107. /* SelectedObject
  1108.  * --------------
  1109.  *
  1110.  * Return a pointer to the currently selected object.
  1111.  *
  1112.  * CUSTOMIZATION: What a "selected object" is will vary from application
  1113.  *                to application.  You may find it useful to have a function
  1114.  *                like this.  In your application it may be necessary to
  1115.  *                actually create an OBJ structure based on what data the
  1116.  *                user has selected from the document (by highlighting some
  1117.  *                text for example).  
  1118.  *
  1119.  */
  1120. LPOBJ SelectedObject (void)
  1121. {
  1122.    return HwndToLpobj (SelectedObjectWindow());
  1123. }
  1124.  
  1125.  
  1126.  
  1127.  
  1128. /* SelectedObjectWindow
  1129.  * --------------------
  1130.  *
  1131.  * Return a handle to the window for the currently selected object.
  1132.  * The GetWindow calls returns a handle to the main window's first child,
  1133.  * which is the selected object's window.  
  1134.  *
  1135.  * CUSTOMIZATION: Server Demo specific
  1136.  *
  1137.  */
  1138. HWND SelectedObjectWindow (void)
  1139. {
  1140.    return GetWindow (hwndMain, GW_CHILD);
  1141. }
  1142.  
  1143.  
  1144.  
  1145. /* SetHiMetricFields
  1146.  * -----------------
  1147.  *
  1148.  * Adjust the nHiMetricWidth and nHiMetricHeight fields of a NATIVE structure
  1149.  * so that they are equivalent to the nWidth and nHeight fields.
  1150.  * The negative sign in the last line is necessary because the positive 
  1151.  * y direction is toward the top of the screen in MM_HIMETRIC mode.
  1152.  *
  1153.  * LPOBJ lpobj - Pointer to the object whose native data will be adjusted
  1154.  *
  1155.  * CUSTOMIZATION: Server Demo specific, although you may need a function like
  1156.  *                this if you keep track of the size of an object, and an 
  1157.  *                object handler needs to know the object's size in 
  1158.  *                HiMetric units.
  1159.  *
  1160.  *
  1161.  */
  1162. void SetHiMetricFields (LPOBJ lpobj)
  1163. {
  1164.    POINT pt;
  1165.    
  1166.    pt.x = lpobj->native.nWidth;
  1167.    pt.y = lpobj->native.nHeight;
  1168.    DeviceToHiMetric (hwndMain, &pt);
  1169.    lpobj->native.nHiMetricWidth  = pt.x;
  1170.    lpobj->native.nHiMetricHeight = pt.y;
  1171. }
  1172.  
  1173.  
  1174.  
  1175. /* SkipBlanks
  1176.  * ----------
  1177.  * 
  1178.  * LPSTR *plpsz - Pointer to a pointer to a character
  1179.  *
  1180.  * Increment *plpsz past any blanks in the character string.
  1181.  * This function is used in ProcessCmdLine.
  1182.  *
  1183.  */
  1184. static void SkipBlanks (LPSTR *plpsz)
  1185. {
  1186.    while (**plpsz && **plpsz == ' ')
  1187.       (*plpsz)++;
  1188. }
  1189.  
  1190.  
  1191.  
  1192. /* UpdateObjMenus
  1193.  * ---------------
  1194.  *
  1195.  * Grey or Ungrey menu items depending on the existence of at least one 
  1196.  * object in the document.
  1197.  *
  1198.  * CUSTOMIZATION: Server Demo specific
  1199.  *
  1200.  */
  1201. static void UpdateObjMenus (void)
  1202. {
  1203.     static BOOL fObjMenusEnabled = TRUE;
  1204.     BOOL        fOneObjExists; // Does at least one object exist?
  1205.     WORD        wEnable;
  1206.     HMENU       hMenu;
  1207.  
  1208.     fOneObjExists = (SelectedObjectWindow() != NULL);
  1209.     if (fOneObjExists == fObjMenusEnabled)
  1210.     {
  1211.          // Nothing has changed.
  1212.          return;
  1213.     }
  1214.  
  1215.     wEnable = (fOneObjExists ? MF_ENABLED : MF_GRAYED);
  1216.  
  1217.     hMenu = GetMenu(hwndMain);
  1218.     EnableMenuItem(hMenu, menuposColor, MF_BYPOSITION | wEnable);
  1219.  
  1220.     hMenu = GetSubMenu(GetMenu(hwndMain), menuposFile);
  1221.     EnableMenuItem(hMenu, IDM_SAVE,   MF_BYCOMMAND | wEnable);
  1222.     EnableMenuItem(hMenu, IDM_SAVEAS, MF_BYCOMMAND | wEnable);
  1223.  
  1224.     hMenu = GetSubMenu(GetMenu(hwndMain), menuposEdit);
  1225.     EnableMenuItem(hMenu, IDM_CUT,     MF_BYCOMMAND | wEnable);
  1226.     EnableMenuItem(hMenu, IDM_COPY,    MF_BYCOMMAND | wEnable);
  1227.     EnableMenuItem(hMenu, IDM_DELETE,  MF_BYCOMMAND | wEnable);
  1228.  
  1229.     hMenu = GetSubMenu(GetMenu(hwndMain), menuposObject);
  1230.     EnableMenuItem(hMenu, IDM_NEXTOBJ, MF_BYCOMMAND | wEnable);
  1231.  
  1232.     DrawMenuBar (hwndMain);
  1233.     fObjMenusEnabled = fOneObjExists;
  1234. }
  1235.  
  1236.  
  1237.  
  1238. /* Wait
  1239.  * ----
  1240.  *
  1241.  * Dispatch messages until the given flag is set to FALSE.
  1242.  * One use of this function is to wait until a Release method is called
  1243.  * after a function has returned OLE_WAIT_FOR_RELEASE.
  1244.  *
  1245.  * BOOL *pf - Pointer to the flag being waited on.
  1246.  *
  1247.  * CUSTOMIZATION: The use of OleUnblockServer is for illustration only.
  1248.  *                Since Server Demo does not call OleBlockServer, there 
  1249.  *                will never be any messages in the OLE queue.
  1250.  *
  1251.  */
  1252. void Wait (BOOL *pf)
  1253. {
  1254.    MSG msg;
  1255.    BOOL fMoreMsgs = FALSE;
  1256.  
  1257.    *pf = TRUE;
  1258.    while (*pf==TRUE)
  1259.    {
  1260.       OleUnblockServer (srvrMain.lhsrvr, &fMoreMsgs);
  1261.       if (!fMoreMsgs)
  1262.       // if there are no more messages in the OLE queue, go to system queue
  1263.       {
  1264.          if (GetMessage (&msg, NULL, NULL, NULL))
  1265.          {
  1266.             TranslateMessage (&msg);
  1267.             DispatchMessage (&msg);
  1268.          }
  1269.       }
  1270.    }
  1271. }
  1272.  
  1273. static BOOL FailedUpdate(HWND hwnd)
  1274. {
  1275.   BOOL    bRet;
  1276.   FARPROC lpfn;
  1277.  
  1278.   lpfn = MakeProcInstance(fnFailedUpdate,hInst);
  1279.   bRet = DialogBox(hInst, "FailedUpdate", hwnd, lpfn);
  1280.   FreeProcInstance(lpfn);
  1281.   return(bRet);
  1282.  
  1283. }
  1284.  
  1285. BOOL FAR PASCAL fnFailedUpdate (HWND hDlg, WORD message, WORD wParam, DWORD lParam)
  1286. {
  1287.  
  1288.    switch (message) 
  1289.    {
  1290.       case WM_COMMAND:
  1291.          switch (wParam) 
  1292.          {
  1293.                case IDCANCEL:
  1294.                case IDD_CONTINUEEDIT:
  1295.                    EndDialog(hDlg, TRUE);
  1296.                    break;
  1297.  
  1298.                case IDD_UPDATEEXIT:
  1299.                    EndDialog(hDlg, FALSE);
  1300.                    break;
  1301.  
  1302.                default:
  1303.                    break;
  1304.          }
  1305.          break;
  1306.  
  1307.        case WM_INITDIALOG:
  1308.        {
  1309.           char szMsg[200];
  1310.  
  1311.           szMsg[0] = NULL;
  1312.  
  1313.           wsprintf(
  1314.                szMsg, 
  1315.                "This %s document can only be updated when you exit %s.",
  1316.                (LPSTR) szClient,
  1317.                (LPSTR) szAppName
  1318.           );
  1319.  
  1320.           SetDlgItemText(hDlg, IDD_TEXT, szMsg);
  1321.           return TRUE; 
  1322.        }
  1323.        
  1324.       default:
  1325.            break;
  1326.    }
  1327.  
  1328.    return FALSE;
  1329. }
  1330.  
  1331.  
  1332.  
  1333.  
  1334.